package EA.testEAs;
import EA.*;
import EA.testproblems.*;
import EA.operators.selection.*;
import EA.recording.*;
import java.util.Hashtable;
import RKUjava.datastructures.RKUVector;
import RKUjava.util.*;
import RKUjava.lang.RKUCloneable;
import Visualization.plot.*;

/** Implements a standard GA. It is possible to run the GA with either bit 
    representation or realvector representation.
    The following is a simple implementation of the main class.<br>
    <pre>
    import EA.*;
    import EA.testproblems.*;
    import EA.testEAs.StandardGA;
    
    public class standardga
    {
      &nbsp;&nbsp;static NumericalProblem curproblem;
      &nbsp;&nbsp;static StandardGA sga;
      &nbsp;&nbsp;static BatchJobScheduler BJS;
    
      &nbsp;&nbsp;public static void main(String argv[])
        &nbsp;&nbsp;{
	  &nbsp;&nbsp;&nbsp;&nbsp;if (argv.length==0){
	    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((new StandardGA()).getDefaultSettings());
	    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);
	  &nbsp;&nbsp;&nbsp;&nbsp;}
	  &nbsp;&nbsp;&nbsp;&nbsp;curproblem = new UrsemMultimodal1();
  	  &nbsp;&nbsp;&nbsp;&nbsp;sga = new StandardGA(curproblem);
	  &nbsp;&nbsp;&nbsp;&nbsp;BJS = new BatchJobScheduler(sga);
	  &nbsp;&nbsp;&nbsp;&nbsp;BJS.startScheduler(argv);
	  &nbsp;&nbsp;&nbsp;&nbsp;System.exit(0);
        &nbsp;&nbsp;}
    }</pre>

    @see EA.BitNumericalGenome
    @see EA.RealNumericalGenome
*/
public class StandardGA implements BatchJobEA
{

  /** Representation type. (Default = 0)<br>
      0 = Realvalue vectors with RealNumericalGenome.<br>
      1 = Bitrepresented vectors with BitNumericalGenome.<br>
  */
  public int representationtype = 0;
    
  /** The current problem. */
  public NumericalProblem curproblem;

  /** The current framework. */
  public NumericalFramework nf;
    
  /** Create a standard GA.<br><b>Note:</b> Remember to set curproblem. */
  public StandardGA()
    {
      super();
    }

  /** Create a standard GA with the given problem. */
  public StandardGA(NumericalProblem aproblem)
    {
      super();
      curproblem = aproblem;
    }

  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;

      if ((curstr = (String)settings.get("representationtype"))!=null) {
	representationtype = (new Integer(curstr)).intValue();
      }

      switch (representationtype) {
      case 0:
	nf = new RealStandardGAFramework(curproblem);
	((RealStandardGAFramework)nf).theGA = this;
	break;
      case 1:
	nf = new BitStandardGAFramework(curproblem);
	((BitStandardGAFramework)nf).theGA = this;
	break;
      }
      ((BatchJobEA)nf).setSettings(settings);

    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      RealStandardGAFramework f = new RealStandardGAFramework();
      StringBuffer res = new StringBuffer();

      res.append(BatchJobScheduler.getDefaultSettings());
      res.append("#################################################################\n");
      res.append("# ------------- Algorithmic settings ----------------------------\n");
      res.append("\n");
      res.append("# Problem name\n");
      res.append("problemname = UrsemMultimodal1\n");
      res.append("\n");
      res.append("# Print information to stdout (true/false)\n");
      res.append("verbose = "+f.verbose+"\n");
      res.append("\n");
      res.append("# Representation type\n");
      res.append("#  0 = Real valued vectors (RealNumericalGenome).\n");
      res.append("#  1 = Binary encoded vectors (BitNumericalGenome).\n");
      res.append("representationtype = "+representationtype+"\n");
      res.append("\n");
      res.append("# Number of bits per variable if bit representation is used\n");
      res.append("bitspervariable = 20\n");
      res.append("\n");      
      res.append("# Probability for mutation\n");
      res.append("p_m = "+f.p_m+"\n");
      res.append("\n");
      res.append("# Probability for crossover\n");
      res.append("p_c = "+f.p_c+"\n");
      res.append("\n");
      res.append("# Maximal number of iterations\n");
      res.append("maxiterations = "+f.maxiterations+"\n");
      res.append("\n");
      res.append("# Initial number of individuals\n");
      res.append("initialpopsize = "+f.initialpopsize+"\n");
      res.append("\n");
      res.append("# Display graph of fitness and mean for each run.\n");
      res.append("# 0 = Don't display graph.\n");
      res.append("# 1 = Display graph of fitness & mean.\n");
      res.append("displaygraph = 1\n\n");
      res.append("# Display trajectory graph of best individual's position.\n");
      res.append("# 0 = Don't display graph.\n");
      res.append("# 1 = Display graph of position.\n");
      res.append("displaybest = 1\n\n");

      return res.toString();
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {};

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
      ((BatchJobEA)nf).finalizeBatchJobs();
    };


  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {
      ((BatchJobEA)nf).initializeRunSeries();
    };

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {
      ((BatchJobEA)nf).finalizeRunSeries();
    };

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      ((BatchJobEA)nf).initializeAndStartRun();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
      ((BatchJobEA)nf).finalizeRun();
    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      return ((BatchJobEA)nf).getDataAsText();
    };
}

class RealStandardGAFramework extends RealNumericalFramework implements BatchJobEA, DataPlot2DExtraction
{

  // True if the info should be printed to stdout
  boolean verbose;
    
  // Probability for mutation
  public double p_m = 0.05;
    
  // Probability for crossover
  public double p_c = 0.9;

  // Should we use elitism
  public boolean elitism = true; 

  // Maximal number of iterations
  public int maxiterations = 200;
    
  // Initial number of individuals
  public int initialpopsize = 100;

  // Is this problem a maximization problem.
  public boolean ismaximization = true;

  public boolean isdynamicproblem = false;

  // Graphwindow control.
  public int displaygraph = 0;

  // Graphwindow control.
  public int displaybest = 0;

  DataPlot2D curplotter, curpeakplotter;

  public NumericalProblem curproblem;

  public StandardGAIndividual[] population;

  public StandardGA theGA;

  private SequenceTable results1;

  /** Create a new framework. */
  public RealStandardGAFramework()
    {
      super();
    }

  /** Create a new framework. */
  public RealStandardGAFramework(NumericalProblem numproblem)
    {
      super(numproblem);
      int i;
      double maxi = Double.NEGATIVE_INFINITY, mini = Double.POSITIVE_INFINITY;

      curproblem = numproblem;
      ismaximization = curproblem.ismaximization;
      curplotter = new DataPlot2D(this, 0);
      curpeakplotter = new DataPlot2D(this, 1);

      for (i=0;i<curproblem.knownmaxima.length;i++) {
	if (maxi<curproblem.knownmaxima[i].getFitness())
	  maxi = curproblem.knownmaxima[i].getFitness();
      }

      for (i=0;i<curproblem.knownminima.length;i++) {
	if (mini>curproblem.knownminima[i].getFitness())
	  mini = curproblem.knownminima[i].getFitness();
      }

      if (maxi != Double.NEGATIVE_INFINITY)
	curplotter.setUpperY(maxi);

      if (mini != Double.POSITIVE_INFINITY)
	curplotter.setLowerY(mini);

      if (curproblem.dimensions==2) {
	curpeakplotter.setLowerX(curproblem.intervals[0].min);
	curpeakplotter.setUpperX(curproblem.intervals[0].max);
	curpeakplotter.setLowerY(curproblem.intervals[1].min);
	curpeakplotter.setUpperY(curproblem.intervals[1].max);
      }
    }

  public void Framework_doEA_inner()
    {
      statistics();
      if (elitism)
	keepElite();
      recombine();
      alter();
      selection();
      if (elitism)
	restoreElite();
      evaluate();

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).updateProblem();
    }

  StandardGAIndividual bestind;

  public void keepElite()
  {
    int i;
    bestind = population[0];

    for (i=1;i<initialpopsize;i++) {
      if (curproblem.ismaximization && bestind.getFitness()<population[i].getFitness()) {
	bestind = population[i];
      }
      else if (!curproblem.ismaximization && bestind.getFitness()>population[i].getFitness()) {
	bestind = population[i];
      }
    }
    bestind = (StandardGAIndividual)bestind.clone();
  }

  public void restoreElite()
  {
    int i;
    int worstindex = 0;
    StandardGAIndividual worstind;

    worstind = population[0];

    for (i=1;i<initialpopsize;i++) {
      if (curproblem.ismaximization && worstind.getFitness()>population[i].getFitness()) {
	worstind = population[i];
	worstindex = i;
      }
      else if (!curproblem.ismaximization && worstind.getFitness()<population[i].getFitness()) {
	worstind = population[i];
	worstindex = i;
      }
    }
    population[worstindex] = bestind;
  }


  public void statistics() 
    {
      StandardGAIndividual best = null;
      int i;

      for (i=0;i<initialpopsize;i++) {
	if (best == null)
	  best = population[i];
	else {
	  if ((ismaximization && best.getFitness()<population[i].getFitness()) || (!ismaximization && best.getFitness()>population[i].getFitness())) {
	    best = population[i];
	  }
	}
      }

      if (best == null) {
	System.out.println("best not found");
      }
      results1.initializeRow();
      results1.updateLastRow(0,iteration);
      results1.updateLastRow(1,best.getFitness());
      results1.updateLastRow(2,best.getPos());
      results1.updateLastRow(2+curproblem.dimensions, PopulationMeasurements.calcMean(population));
      results1.updateLastRow(3+curproblem.dimensions, PopulationMeasurements.calcStandardDeviation(population));
	
      if (verbose)
	System.out.println("Bestfit="+best.getFitness()+"  "+RKUStringUtils.arrayToString(best.getPos()));

    }

  public boolean terminate()
    {
      return iteration<maxiterations-1;
    }

  public void Framework_initialize_inner()
    {
      int i;
      population = new StandardGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	population[i] = new StandardGAIndividual(this, true, theGA.representationtype);
      };
      evaluate();

      results1 = new SequenceTable("standardGA");
      results1.addColumn(new SequenceTableColumn("Generation"));
      results1.addColumn(new SequenceTableColumn("Bestfit"));
      results1.addColumns(curproblem.getSequenceTableColumns(""));
      results1.addColumn(new SequenceTableColumn("Mean"));
      results1.addColumn(new SequenceTableColumn("Std deviation"));

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).resetProblem();

    };

  /** BETA style inner call for summarize().
   */
  public void Framework_summarize_inner()
    {
      statistics();
    }

  /** Override this in your implementation. */
  public void selection()
    {
      StandardGAIndividual[] newpop = new StandardGAIndividual[initialpopsize];
      TournamentSelection.selectInto(population, initialpopsize, ismaximization, true, newpop);
      population = newpop;
    };

  StandardGAIndividual[] parents = new StandardGAIndividual[2];

  /* Perform crossover on nations. */
  public void recombine()
    {
      int i;
      StandardGAIndividual[] newpop;
      newpop = new StandardGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	if (UsefulRoutines.randomBiasedBoolean(p_c)) {
	  RandomSelection.selectInto(population, 2, ismaximization, false, parents);
	  newpop[i] = parents[0].crossover(parents[0], parents[1]);
	}
	else
	  newpop[i] = population[i];
      }
      population = newpop;
    }

  /** Mutate all individuals. */
  public void alter()
    {
      int i;

      for (i = 0; i<initialpopsize;i++) {
	population[i].mutate(p_m, 1.0/(1+iteration));
      }
    } 

  /** Evaluate all individuals. */
  public void evaluate()
    {
      double fitsum;
      int i;

      fitsum = 0;

      for (i = 0; i<initialpopsize;i++) {
	fitsum += population[i].getFitness();
      }
      //	System.out.println("Fitsum = "+fitsum);
    }

  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;

      if ((curstr = (String)settings.get("verbose"))!=null) {
	verbose = (new Boolean(curstr)).booleanValue();
      }

      if( (curstr = (String)settings.get("p_m"))!=null) {
	p_m = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("p_c"))!=null) {
	p_c = (new Double(curstr)).doubleValue();
      }

      if ((curstr = (String)settings.get("elitism"))!=null) {
	elitism = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("maxiterations"))!=null) {
	maxiterations = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("initialpopsize"))!=null) {
	initialpopsize = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("problemname"))!=null) {
	  curproblem = NumericalProblemSelector.selectProblem(curstr);
	  setProblem(curproblem);
	  ismaximization = curproblem.ismaximization;
      }

      if ((curstr = (String)settings.get("displaygraph"))!=null) {
	displaygraph = (new Integer(curstr)).intValue();
      }

      if (curproblem.dimensions==2 && ((curstr = (String)settings.get("displaybest"))!=null)) {
	displaybest = (new Integer(curstr)).intValue();
      }

      if (curproblem instanceof DynamicNumericalProblem) {
	isdynamicproblem = true;
	((DynamicNumericalProblem)curproblem).setSettings(settings, this);
      }
      else
	isdynamicproblem = false;

    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      return "";
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {
    };

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
      curplotter.endPlot();
    };

  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {};

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {};

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      doEA();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
      switch(displaygraph){ 
      case 0: // Do nothing
	break;
      case 1:
	curplotter.updatePlot();
	break;
      }

      switch(displaybest){ 
      case 0: // Do nothing
	break;
      case 1:
	curpeakplotter.updatePlot();
	break;
      }

    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ResultSet
      @see EA.recording.Measurement
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      Object[] res = new Object[1];

      res[0] = results1;
      return res;
    };

  // ************* Plot interface **********************************

  /** Extract the data as a 2 dimensional array of objects. <br>
      <b>Note:</b> All second-indexes arrays must have equal length.
  */
  public synchronized Object[][] extract2DAsObjects(int plotternumber)
    {
      Object[][] res = new Object[2][0];
      switch (plotternumber) {
      case 0:
	res[0] = (results1.getColumn(1)).getDataAsArray();
	res[1] = (results1.getColumn(2+curproblem.dimensions)).getDataAsArray();
	break;
      case 1:
	res[0] = (results1.getColumn(2)).getDataAsArray();
	res[1] = (results1.getColumn(3)).getDataAsArray();
	break;
      }	    
      return res;
    };

  /** Extract the data as a 2 dimensional array of doubles.<br>
      <b>Note:</b> All second-indexes arrays must have equal length. */
  public synchronized double[][] extract2DAsDoubles(int plotternumber)
    {
      return null;
    };

  int[][] resultstypes = {{0,0},{0,0}};
  int[][] trajectorytypes = {{2,0},{2,0}};

  public synchronized int[][] extract2DDataTypes(int plotternumber)
    {
      switch(plotternumber)
	{
	case 0:
	  return resultstypes;
	case 1: 
	  return trajectorytypes;
	}
      return resultstypes;
    };

  /** Extract the name of a graph given an index. */
  public String extract2DName(int index, int plotternumber)
    {
      switch (plotternumber) {
      case 0:
	switch(index) {
	case 0:
	  return "Bestfit";
	case 1:
	  return "Mean";
	}
	break;
      case 1:
	return "Best pos";
      }
      return "";
    };


}

class BitStandardGAFramework extends BitNumericalFramework implements BatchJobEA, DataPlot2DExtraction
{

  // True if the info should be printed to stdout
  boolean verbose;
    
  // Probability for mutation
  public double p_m = 0.05;
    
  // Number of bits per variable
  public int bitspervariable = 20;

  // Probability for crossover
  public double p_c = 0.9;

  // Should we use elitism
  public boolean elitism = true; 

  // Maximal number of iterations
  public int maxiterations = 200;
    
  // Initial number of individuals
  public int initialpopsize = 100;

  // Is this problem a maximization problem.
  public boolean ismaximization = true;

  public boolean isdynamicproblem = false;

  // Graphwindow control.
  public int displaygraph = 0;

  // Graphwindow control.
  public int displaybest = 0;

  DataPlot2D curplotter, curpeakplotter;

  public NumericalProblem curproblem;

  public StandardGAIndividual[] population;

  public StandardGA theGA;

  private SequenceTable results1;

  /** Create a new framework. */
  public BitStandardGAFramework()
    {
      super();
    }

  /** Create a new framework. */
  public BitStandardGAFramework(NumericalProblem numproblem)
    {
      int i;
      double maxi = Double.NEGATIVE_INFINITY, mini = Double.POSITIVE_INFINITY;
      setProblem(numproblem);
      setBitsPerVariable(bitspervariable);

      curproblem = numproblem;
      ismaximization = curproblem.ismaximization;
      curplotter = new DataPlot2D(this, 0);
      curpeakplotter = new DataPlot2D(this, 1);

      for (i=0;i<curproblem.knownmaxima.length;i++) {
	if (maxi<curproblem.knownmaxima[i].getFitness())
	  maxi = curproblem.knownmaxima[i].getFitness();
      }

      for (i=0;i<curproblem.knownminima.length;i++) {
	if (mini>curproblem.knownminima[i].getFitness())
	  mini = curproblem.knownminima[i].getFitness();
      }

      if (maxi != Double.NEGATIVE_INFINITY)
	curplotter.setUpperY(maxi);

      if (mini != Double.POSITIVE_INFINITY)
	curplotter.setLowerY(mini);

      if (curproblem.dimensions==2) {
	curpeakplotter.setLowerX(curproblem.intervals[0].min);
	curpeakplotter.setUpperX(curproblem.intervals[0].max);
	curpeakplotter.setLowerY(curproblem.intervals[1].min);
	curpeakplotter.setUpperY(curproblem.intervals[1].max);
      }
    }

  public void Framework_doEA_inner()
    {
      statistics();
      if (elitism)
	keepElite();
      recombine();
      alter();
      selection();
      if (elitism)
	restoreElite();
      evaluate();

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).updateProblem();
    }

  StandardGAIndividual bestind;

  public void keepElite()
  {
    int i;
    bestind = population[0];

    for (i=1;i<initialpopsize;i++) {
      if (curproblem.ismaximization && bestind.getFitness()<population[i].getFitness()) {
	bestind = population[i];
      }
      else if (!curproblem.ismaximization && bestind.getFitness()>population[i].getFitness()) {
	bestind = population[i];
      }
    }
    bestind = (StandardGAIndividual)bestind.clone();
  }

  public void restoreElite()
  {
    int i;
    int worstindex = 0;
    StandardGAIndividual worstind;

    worstind = population[0];

    for (i=1;i<initialpopsize;i++) {
      if (curproblem.ismaximization && worstind.getFitness()>population[i].getFitness()) {
	worstind = population[i];
	worstindex = i;
      }
      else if (!curproblem.ismaximization && worstind.getFitness()>population[i].getFitness()) {
	worstind = population[i];
	worstindex = i;
      }
    }
    population[worstindex] = bestind;
  }


  public void statistics() 
    {
      StandardGAIndividual best = null;
      int i;

      for (i=0;i<initialpopsize;i++) {
	if (best == null)
	  best = population[i];
	else {
	  if ((ismaximization && best.getFitness()<population[i].getFitness()) || (!ismaximization && best.getFitness()>population[i].getFitness())) {
	    best = population[i];
	  }
	}
      }

      if (best == null) {
	System.out.println("best not found");
      }
      results1.initializeRow();
      results1.updateLastRow(0,iteration);
      results1.updateLastRow(1,best.getFitness());
      results1.updateLastRow(2,best.getPos());
      results1.updateLastRow(2+curproblem.dimensions, PopulationMeasurements.calcMean(population));
      results1.updateLastRow(3+curproblem.dimensions, PopulationMeasurements.calcStandardDeviation(population));
	
      if (verbose)
	System.out.println("Bestfit="+best.getFitness()+"  "+RKUStringUtils.arrayToString(best.getPos()));

    }

  public boolean terminate()
    {
      return iteration<maxiterations-1;
    }

  public void Framework_initialize_inner()
    {
      int i;
      population = new StandardGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	population[i] = new StandardGAIndividual(this, true, theGA.representationtype);
      };
      evaluate();

      results1 = new SequenceTable("standardGA");
      results1.addColumn(new SequenceTableColumn("Generation"));
      results1.addColumn(new SequenceTableColumn("Bestfit"));
      results1.addColumns(curproblem.getSequenceTableColumns(""));
      results1.addColumn(new SequenceTableColumn("Mean"));
      results1.addColumn(new SequenceTableColumn("Std deviation"));

      if (isdynamicproblem)
	((DynamicNumericalProblem)curproblem).resetProblem();

    };

  /** BETA style inner call for summarize().
   */
  public void Framework_summarize_inner()
    {
      statistics();
    }

  /** Override this in your implementation. */
  public void selection()
    {
      StandardGAIndividual[] newpop = new StandardGAIndividual[initialpopsize];
      TournamentSelection.selectInto(population, initialpopsize, ismaximization, true, newpop);
      population = newpop;
    };

  StandardGAIndividual[] parents = new StandardGAIndividual[2];

  /* Perform crossover on nations. */
  public void recombine()
    {
      int i;
      StandardGAIndividual[] newpop;
      newpop = new StandardGAIndividual[initialpopsize];

      for (i = 0;i<initialpopsize;i++) {
	if (UsefulRoutines.randomBiasedBoolean(p_c)) {
	  RandomSelection.selectInto(population, 2, ismaximization, false, parents);
	  newpop[i] = parents[0].crossover(parents[0], parents[1]);
	}
	else
	  newpop[i] = population[i];
      }
      population = newpop;
    }

  /** Mutate all individuals. */
  public void alter()
    {
      int i;

      for (i = 0; i<initialpopsize;i++) {
	population[i].mutate(p_m);
      }
    } 

  /** Evaluate all individuals. */
  public void evaluate()
    {
      double fitsum;
      int i;

      fitsum = 0;

      for (i = 0; i<initialpopsize;i++) {
	fitsum += population[i].getFitness();
      }
      //	System.out.println("Fitsum = "+fitsum);
    }

  // **** BatchJob implementation *****************************

  /** Set the settings for the algorithm. The passed hashtable contains
      only String objects which are all related to the input file given 
      to the scheduler. 
  */
  public void setSettings(Hashtable settings)
    {
      String curstr;

      if ((curstr = (String)settings.get("verbose"))!=null) {
	verbose = (new Boolean(curstr)).booleanValue();
      }

      if( (curstr = (String)settings.get("p_m"))!=null) {
	p_m = (new Double(curstr)).doubleValue();
      }

      if( (curstr = (String)settings.get("p_c"))!=null) {
	p_c = (new Double(curstr)).doubleValue();
      }

      if ((curstr = (String)settings.get("elitism"))!=null) {
	elitism = (new Boolean(curstr)).booleanValue();
      }

      if ((curstr = (String)settings.get("maxiterations"))!=null) {
	maxiterations = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("initialpopsize"))!=null) {
	initialpopsize = (new Integer(curstr)).intValue();
      }

      if ((curstr = (String)settings.get("bitspervariable"))!=null) {
	bitspervariable = (new Integer(curstr)).intValue();
	setBitsPerVariable(bitspervariable);
      }

      if ((curstr = (String)settings.get("problemname"))!=null) {
	  curproblem = NumericalProblemSelector.selectProblem(curstr);
	  setProblem(curproblem);
	  ismaximization = curproblem.ismaximization;
      }

      if ((curstr = (String)settings.get("displaygraph"))!=null) {
	displaygraph = (new Integer(curstr)).intValue();
      }

      if (curproblem.dimensions==2 && ((curstr = (String)settings.get("displaybest"))!=null)) {
	displaybest = (new Integer(curstr)).intValue();
      }

      if (curproblem instanceof DynamicNumericalProblem) {
	isdynamicproblem = true;
	((DynamicNumericalProblem)curproblem).setSettings(settings, this);
      }
      else
	isdynamicproblem = false;

    };

  /** Get the default settings in the BatchJobScheduler format. This 
      method can be used to reconstruct an input file for the scheduler. 
  */
  public String getDefaultSettings()
    {
      return "";
    };

  /** Initialize a batchjob. This is called once before any run is performed.
   */
  public void initializeBatchJobs()
    {
    };

  /** Finalize a batchjob. This is called once after all runs are performed.
   */
  public void finalizeBatchJobs()
    {
      curplotter.endPlot();
    };

  /** Initialize a run series. This is called once before the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void initializeRunSeries()
    {};

  /** Finalize a run series. This is called once after the specified 
      number of runs are performed. (BJSruns in the batchfile)
  */
  public void finalizeRunSeries()
    {};

  /** Initialize and start a single run of the algorithm. You can 
      usually just call doEA() from your framework.
  */
  public void initializeAndStartRun()
    {
      doEA();
    };

  /** Finalize the single run of the algorithm. This is called immediately
      after the initializeAndStartRun(). It can be used to reset 
      measurements, increase counters, etc.
  */
  public void finalizeRun()
    {
      switch(displaygraph){ 
      case 0: // Do nothing
	break;
      case 1:
	curplotter.updatePlot();
	break;
      }

      switch(displaybest){ 
      case 0: // Do nothing
	break;
      case 1:
	curpeakplotter.updatePlot();
	break;
      }

    };

  /** Get the run data as text. Your implementation must return
      an array of objects that each implements the interface ConvertToText from the package
      EA.recording. You can use the classes found in EA.recording or 
      implement your own classes.
      @see EA.recording.ResultSet
      @see EA.recording.Measurement
      @see EA.recording.ConvertToText
  */
  public Object[] getDataAsText()
    {
      Object[] res = new Object[1];

      res[0] = results1;
      return res;
    };

  // ************* Plot interface **********************************

  /** Extract the data as a 2 dimensional array of objects. <br>
      <b>Note:</b> All second-indexes arrays must have equal length.
  */
  public synchronized Object[][] extract2DAsObjects(int plotternumber)
    {
      Object[][] res = new Object[2][0];
      switch (plotternumber) {
      case 0:
	res[0] = (results1.getColumn(1)).getDataAsArray();
	res[1] = (results1.getColumn(2+curproblem.dimensions)).getDataAsArray();
	break;
      case 1:
	res[0] = (results1.getColumn(2)).getDataAsArray();
	res[1] = (results1.getColumn(3)).getDataAsArray();
	break;
      }	    
      return res;
    };

  /** Extract the data as a 2 dimensional array of doubles.<br>
      <b>Note:</b> All second-indexes arrays must have equal length. */
  public synchronized double[][] extract2DAsDoubles(int plotternumber)
    {
      return null;
    };

  int[][] resultstypes = {{0,0},{0,0}};
  int[][] trajectorytypes = {{2,0},{2,0}};

  public synchronized int[][] extract2DDataTypes(int plotternumber)
    {
      switch(plotternumber)
	{
	case 0:
	  return resultstypes;
	case 1: 
	  return trajectorytypes;
	}
      return resultstypes;
    };

  /** Extract the name of a graph given an index. */
  public String extract2DName(int index, int plotternumber)
    {
      switch (plotternumber) {
      case 0:
	switch(index) {
	case 0:
	  return "Bestfit";
	case 1:
	  return "Mean";
	}
	break;
      case 1:
	return "Best pos";
      }
      return "";
    };


}


class StandardGAIndividual extends Individual implements RKUCloneable, RKUValuation, NumericalInspector
{

  /** Create a new StandardGAIndividual. 
      @param frame The framework for this individual.
      @param initialize True if you want to create a new Bit/Real-NumericalGenome.
      @param reptype The type of representation.
  */
  public StandardGAIndividual(NumericalFramework frame, boolean initialize, int reptype)
    {
      super(frame);

      if (initialize) {
	switch(reptype) {
	case 0:
	  genome = new RealNumericalGenome((RealNumericalFramework)frame,true);
	  break;
	case 1:
	  genome = new BitNumericalGenome((BitNumericalFramework)frame,true);
	  break;
	}
      }
    }

  public static StandardGAIndividual crossover(StandardGAIndividual individual1, StandardGAIndividual individual2)
    {
      StandardGAIndividual res;

      res = new StandardGAIndividual((NumericalFramework)individual1.framework, false, 0);

      if (individual1.genome instanceof RealNumericalGenome) {
	res.genome = RealNumericalGenome.crossover(individual1.genome, individual2.genome);
      }
      else if (individual1.genome instanceof BitNumericalGenome) {
	res.genome = BitNumericalGenome.crossover(individual1.genome, individual2.genome);
      };
      return res;
    };

  public double getFitness()
    {
      return ((NumericalGenome)genome).getFitness();
    }

  public void mutate(double p_m, double var)
    {
      ((RealNumericalGenome)genome).mutate(p_m,var);
    }

  public Object clone()
    {
      StandardGAIndividual res;

      res = new StandardGAIndividual((NumericalFramework)framework, false, 0);
      res.genome = (Genome)(this.genome.clone());
      return res;
    }

  public double value()
    {
      return this.getFitness();
    }

  public double[] getPos()
    {
      return ((NumericalGenome)genome).getPos();
    }

  // Inteface-implementation: NumericalInspector
  public double[] inspectGetPos() { return getPos(); }
  public double inspectGetFitness() { return getFitness(); }
}

